#include <openvdb/openvdb.h>
#include <openvdb/tools/ChangeBackground.h>
#include <openvdb/tools/LevelSetSphere.h>
int main(){
    int a; // TODO

    // ================================= Node Iterator
    using GridType = openvdb::FloatGrid;
    using TreeType = GridType::TreeType;
    using RootType = TreeType::RootNodeType;   // level 3 RootNode
    assert(RootType::LEVEL == 3);
    using Int1Type = RootType::ChildNodeType;  // level 2 InternalNode
    using Int2Type = Int1Type::ChildNodeType;  // level 1 InternalNode
    using LeafType = TreeType::LeafNodeType;   // level 0 LeafNode
    GridType::Ptr grid = openvdb::tools::createLevelSetSphere<openvdb::FloatGrid>(50.0, openvdb::Vec3f(1.5, 2, 3), 0.5, 4.0);
    for (TreeType::NodeIter iter = grid->tree().beginNode(); iter; ++iter) {
        switch (iter.getDepth()) {
        case 0: { RootType* node = nullptr; iter.getNode(node); if (node) a=1; break; }
        case 1: { Int1Type* node = nullptr; iter.getNode(node); if (node) a=2; break; }
        case 2: { Int2Type* node = nullptr; iter.getNode(node); if (node) a=3; break; }
        case 3: { LeafType* node = nullptr; iter.getNode(node); if (node) a=4; break; }
        }
    }

    // ================================ Leaf Node Iterator
    // using GridType = openvdb::FloatGrid;
    // using TreeType = GridType::TreeType;
    // Iterate over references to const LeafNodes.
    for (TreeType::LeafCIter iter = grid->tree().cbeginLeaf(); iter; ++iter) {
        const TreeType::LeafNodeType& leaf1 = *iter;
        a=1;
    }
    // Iterate over references to non-const LeafNodes.
    for (TreeType::LeafIter iter = grid->tree().beginLeaf(); iter; ++iter) {
        TreeType::LeafNodeType& leaf2 = *iter;
        a=2;
    }
    // Iterate over pointers to const LeafNodes.
    for (TreeType::LeafCIter iter = grid->tree().cbeginLeaf(); iter; ++iter) {
        const TreeType::LeafNodeType* leaf3 = iter.getLeaf();
        a=3;
    }
    // Iterate over pointers to non-const LeafNodes.
    for (TreeType::LeafIter iter = grid->tree().beginLeaf(); iter; ++iter) {
        TreeType::LeafNodeType* leaf4 = iter.getLeaf();
        a=4;
    }

    // ======================================= Value Iterator
    using GridType2 = openvdb::Vec3SGrid;
    using TreeType2 = GridType2::TreeType;
    openvdb::Vec3SGrid::Ptr grid3s = openvdb::Vec3SGrid::create();
    // Iterate over all active values but don't allow them to be changed.
    for (GridType2::ValueOnCIter iter = grid3s->cbeginValueOn(); iter.test(); ++iter) {
        const openvdb::Vec3f& value = *iter;
        // Print the coordinates of all voxels whose vector value has
        // a length greater than 10, and print the bounding box coordinates
        // of all tiles whose vector value length is greater than 10.
        if (value.length() > 10.0) {
            if (iter.isVoxelValue()) {
                std::cout << iter.getCoord() << std::endl;
            } else {
                openvdb::CoordBBox bbox;
                iter.getBoundingBox(bbox);
                std::cout << bbox << std::endl;
            }
        }
    }
    // Iterate over and normalize all inactive values.
    for (GridType2::ValueOffIter iter = grid3s->beginValueOff(); iter.test(); ++iter) {
        openvdb::Vec3f value = *iter;
        value.normalize();
        iter.setValue(value);
    }
    // Normalize the (inactive) background value as well.
    openvdb::tools::changeBackground(grid3s->tree(), grid3s->background().unit());

}
